package wheel;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import algorithms.Key;

import exceptions.InitializationExternalKeyException;

public class KeyWheel {
 

    private int id;
    
    /**
     * The list of keys for a wheel.
     */
    private List<Key> keys = new ArrayList<Key>();

    /**
     * Mapping key and pin (effective=true, ineffective=false).
     */
    private Map<Key, Boolean> keyPins = new HashMap<Key, Boolean>();

    /**
     * For the external key.
     */
    private Key position;
    
    /**
     * To know the real used pin.
     */
    private int shiftFromPositionToActiveKey;

    /**
     * The content can be (from the left to the right wheels):
     * <ul>
     * <li>KeyWheel1: ABCDEFGHIJKLMNOPQRSTUVWXYZ</li>
     * <li>KeyWheel2: ABCDEFGHIJKLMNOPQRSTUVXYZ</li>
     * <li>KeyWheel3: ABCDEFGHIJKLMNOPQRSTUVX</li>
     * <li>KeyWheel4: ABCDEFGHIJKLMNOPQRSTU</li>
     * <li>KeyWheel5: ABCDEFGHIJKLMNOPQRS</li>
     * <li>KeyWheel6: ABCDEFGHIJKLMNOPQ</li>
     * </ul>
     * 
     * @param content
     */
    public KeyWheel(int id,String content, int shiftFromPositionToActiveKey) {
	this.id = id;
	this.shiftFromPositionToActiveKey = shiftFromPositionToActiveKey;

	// initialization of the list of keys
	char[] charArray = content.toCharArray();
	for (int i = 0; i < charArray.length; i++) {
	    keys.add(Key.charToKey(charArray[i]));
	}

	// initialization of the iterator
	position = Key.A;

	// initialization of the pins
	for (Key key : keys) {
	    keyPins.put(key, false);
	}
    }

    /**
     * To set the initial value of the external key.
     * 
     * @param key
     * @throws InitializationExternalKeyException
     */
    public void setInitialPosition(Key key) throws InitializationExternalKeyException {
	if (keys.contains(key)) {
	    position = key;
	} else {
	    throw new InitializationExternalKeyException(this, key);
	}
    }

    /**
     * Set the next position of the wheel.
     */
    public void setNextPosition() {
	position = getKeys().get((getKeys().lastIndexOf(position) + 1) % getKeys().size());
    }
    
    public Key getActiveKey(){
	return getKeys().get((getKeys().lastIndexOf(position) + shiftFromPositionToActiveKey) % getKeys().size());
    }

    // ///////////////////////
    // GETTERS and SETTERS //
    // ///////////////////////

    /**
     * @return the keys
     */
    public List<Key> getKeys() {
	return keys;
    }

    /**
     * @param keys
     *        the keys to set
     */
    public void setKeys(List<Key> keys) {
	this.keys = keys;
    }

    /**
     * @return the keyPins
     */
    public Map<Key, Boolean> getKeyPins() {
	return keyPins;
    }

    /**
     * @param keyPins
     *        the keyPins to set
     */
    public void setKeyPins(Map<Key, Boolean> keyPins) {
	this.keyPins = keyPins;
    }

    /**
     * @return the position
     */
    public Key getPosition() {
	return position;
    }
    
    public String toStringToSave() {
	StringBuilder sBuilder = new StringBuilder();
	for(Key key : keys){
	    if(keyPins.get(key)){
		sBuilder.append(key.name());
	    }else{
		sBuilder.append('-');
	    }
	}
	return sBuilder.toString();
    }
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
	return "KeyWheel#" + id;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + id;
	return result;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
	if (this == obj)
	    return true;
	if (obj == null)
	    return false;
	if (getClass() != obj.getClass())
	    return false;
	KeyWheel other = (KeyWheel) obj;
	if (id != other.id)
	    return false;
	return true;
    }

    /**
     * @return the id
     */
    public int getId() {
        return id;
    }
    
    public int getShiftFromPositionToActiveKey(){
	return shiftFromPositionToActiveKey;
    }
    
    
}
